import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
/**
 * 树节点
 */
var TreeNode = /*#__PURE__*/function () {
  function TreeNode(data, options) {
    var _data$this$childrenKe,
      _this = this;
    _classCallCheck(this, TreeNode);
    _defineProperty(this, "origin", void 0);
    _defineProperty(this, "childNodes", []);
    _defineProperty(this, "tree", void 0);
    _defineProperty(this, "parent", void 0);
    _defineProperty(this, "uniqueKey", 'key');
    _defineProperty(this, "childrenKey", 'children');
    this.origin = data;
    if (options.uniqueKey) this.uniqueKey = options.uniqueKey;
    if (options.childrenKey) this.childrenKey = options.childrenKey;
    if (options.parent) this.parent = options.parent;
    if (!options.tree) {
      console.error('options.tree cannnot be undefined');
    }
    this.tree = options.tree;
    ((_data$this$childrenKe = data[this.childrenKey]) !== null && _data$this$childrenKe !== void 0 ? _data$this$childrenKe : []).forEach(function (child) {
      var childNode = new TreeNode(child, {
        uniqueKey: _this.uniqueKey,
        childrenKey: _this.childrenKey,
        parent: _this,
        tree: _this.tree
      });
      _this.childNodes.push(childNode);
    });

    /**
     * @todo 暂时不用 Proxy 代理，第一导致调试不方便，第二会导致测试用例不通过，需要改造
     * 使用 Proxy 代理支持访问原始数据属性
     */
    // return new Proxy(this, {
    //   get(target, propKey) {
    //     if (propKey in target) return target[propKey];
    //     return target.origin[propKey];
    //   },
    // });
  }

  /** 获取属性 */
  _createClass(TreeNode, [{
    key: "getProperty",
    value: function getProperty(propertyKey) {
      return this.origin[propertyKey];
    }

    /** 设置属性 */
  }, {
    key: "setProperty",
    value: function setProperty(propertyKey, propertyValue) {
      return this.origin[propertyKey] = propertyValue;
    }

    /** @todo 暂时使用 get 直接获取视图渲染数据 */
  }, {
    key: "title",
    get: function get() {
      return this.getProperty('title');
    }

    /** @todo 暂时使用 get 直接获取视图渲染数据 */
  }, {
    key: "label",
    get: function get() {
      return this.getProperty('label');
    }

    /** @todo 暂时使用 get 直接获取视图渲染数据 */
  }, {
    key: "value",
    get: function get() {
      return this.getProperty('value');
    }

    /** @todo 暂时每次访问均使用新的引用，以使视图更新 */
  }, {
    key: "children",
    get: function get() {
      return _toConsumableArray(this.childNodes);
    }

    /** 节点唯一标识 */
  }, {
    key: "key",
    get: function get() {
      return this.origin[this.uniqueKey];
    }

    /** 父节点唯一标识 */
  }, {
    key: "parentKey",
    get: function get() {
      var _this$parent;
      return (_this$parent = this.parent) === null || _this$parent === void 0 || (_this$parent = _this$parent.origin) === null || _this$parent === void 0 ? void 0 : _this$parent[this.uniqueKey];
    }

    /** 节点路径 */
  }, {
    key: "nodePath",
    get: function get() {
      var result = [];
      var curr = this;
      while (curr) {
        result.unshift(curr);
        curr = curr.parent;
      }
      return result;
    }

    /** 从 1 开始计数 */
  }, {
    key: "level",
    get: function get() {
      return this.nodePath.length;
    }

    /** 包含自身的兄弟节点 */
  }, {
    key: "siblingsIncludeSelf",
    get: function get() {
      var _this$parent2;
      return !this.parent ? this.tree.nodes : (_this$parent2 = this.parent) === null || _this$parent2 === void 0 ? void 0 : _this$parent2.childNodes;
    }

    /** 去除自身的兄弟节点 */
  }, {
    key: "siblings",
    get: function get() {
      var _this$siblingsInclude,
        _this2 = this;
      return (_this$siblingsInclude = this.siblingsIncludeSelf) === null || _this$siblingsInclude === void 0 ? void 0 : _this$siblingsInclude.filter(function (it) {
        return it !== _this2;
      });
    }

    /** 索引 */
  }, {
    key: "index",
    get: function get() {
      var _this$siblingsInclude2;
      return this.siblingsIncludeSelf ? (_this$siblingsInclude2 = this.siblingsIncludeSelf) === null || _this$siblingsInclude2 === void 0 ? void 0 : _this$siblingsInclude2.indexOf(this) : -1;
    }

    /** 是否可能叶子节点，不适用于懒加载情况 */
  }, {
    key: "isMaybeLeaf",
    get: function get() {
      var _this$childNodes;
      return !((_this$childNodes = this.childNodes) !== null && _this$childNodes !== void 0 && _this$childNodes.length);
    }

    /** 遍历 */
  }, {
    key: "forEach",
    value: function forEach(iteratee) {
      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
        mode: 'pre'
      };
      var mode = options.mode;
      if (mode === 'post') {
        this.childNodes.forEach(function (childNode) {
          childNode.forEach(iteratee, options);
        });
        iteratee(this);
      } else {
        iteratee(this);
        this.childNodes.forEach(function (childNode) {
          return childNode.forEach(iteratee);
        });
      }
    }

    /** 过滤 */
  }, {
    key: "filter",
    value: function filter(predicate) {
      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
        mode: 'pre',
        isTree: false
      };
      var result = [];
      var mode = options.mode,
        isTree = options.isTree;
      if (isTree) {
        var _this$childNodes2;
        // 此方法会更改节点的 childNodes
        // 返回符合过滤条件的根节点
        function postTraverse(curr) {
          var matchedChildren = [];
          curr.childNodes.forEach(function (childNode, i) {
            var _childNode$childNodes;
            postTraverse(childNode);
            if ((_childNode$childNodes = childNode.childNodes) !== null && _childNode$childNodes !== void 0 && _childNode$childNodes.length || predicate(childNode)) matchedChildren.push(childNode);
            if (i === curr.childNodes.length - 1) {
              curr.childNodes = matchedChildren;
            }
          });
        }
        postTraverse(this);
        if ((_this$childNodes2 = this.childNodes) !== null && _this$childNodes2 !== void 0 && _this$childNodes2.length || predicate(this)) result.push(this);
        return result;
      }
      if (mode === 'post') {
        this.childNodes.forEach(function (childNode) {
          var _result;
          var res = childNode.filter(predicate, options);
          (_result = result).push.apply(_result, _toConsumableArray(res));
        });
        if (predicate(this)) result.push(this);
      } else {
        if (predicate(this)) result.push(this);
        this.childNodes.forEach(function (childNode) {
          var filtered = childNode.filter(predicate);
          result = result.concat(filtered);
        });
      }
      return result;
    }

    /** 遍历 */
  }, {
    key: "map",
    value: function map(convert) {
      var result = [];
      result.push(convert(this));
      this.childNodes.forEach(function (childNode) {
        var converted = childNode.map(convert);
        result = result.concat(converted);
      });
      return result;
    }

    /** 转数组 */
  }, {
    key: "toArray",
    value: function toArray() {
      return this.map(function (node) {
        return node;
      });
    }

    /** 转键值对映射 */
  }, {
    key: "toMap",
    value: function toMap() {
      var result = {};
      this.forEach(function (node) {
        result[node.key] = node;
      });
      return result;
    }

    /** 从当前节点及其子孙节点中判断是否包含 */
  }, {
    key: "has",
    value: function has(predicate) {
      var realPredicate = typeof predicate === 'string' ? function (node) {
        return node.key === predicate;
      } : predicate;
      if (realPredicate(this)) return true;
      return this.childNodes.some(function (childNode) {
        return childNode.has(realPredicate);
      });
    }

    /** 通过匹配规则从当前节点及其子孙节点中查找 */
  }, {
    key: "query",
    value: function query(predicate) {
      var realPredicate = typeof predicate === 'string' ? function (node) {
        return node.key === predicate;
      } : predicate;
      if (realPredicate(this)) return this;
      var result;
      this.childNodes.some(function (childNode) {
        var found = childNode.query(realPredicate);
        if (found) {
          result = found;
          return true;
        }
      });
      return result;
    }

    /**
     * 尾部添加子节点（不改变原始数据）
     */
  }, {
    key: "append",
    value: function append(data) {
      if (this.tree.has(data[this.uniqueKey])) {
        throw new Error("".concat(data[this.uniqueKey], " is existed already"));
      }
      var node = new TreeNode(data, {
        uniqueKey: this.uniqueKey,
        childrenKey: this.childrenKey,
        parent: this,
        tree: this.tree
      });
      this.childNodes.push(node);
      return this;
    }

    /**
     * 尾部添加子节点列表（不改变原始数据）
     */
  }, {
    key: "appendChildren",
    value: function appendChildren(datas) {
      var _this3 = this;
      datas.forEach(function (data) {
        if (_this3.tree.has(data[_this3.uniqueKey])) {
          throw new Error("".concat(data[_this3.uniqueKey], " is existed already"));
        }
      });
      datas.forEach(function (data) {
        var node = new TreeNode(data, {
          uniqueKey: _this3.uniqueKey,
          childrenKey: _this3.childrenKey,
          parent: _this3,
          tree: _this3.tree
        });
        _this3.childNodes.push(node);
      });
      return this;
    }

    /**
     * 头部添加子节点（不改变原始数据）
     */
  }, {
    key: "prepend",
    value: function prepend(data) {
      if (this.tree.has(data[this.uniqueKey])) {
        throw new Error("".concat(data[this.uniqueKey], " is existed already"));
      }
      var node = new TreeNode(data, {
        uniqueKey: this.uniqueKey,
        childrenKey: this.childrenKey,
        parent: this,
        tree: this.tree
      });
      this.childNodes.unshift(node);
      return this;
    }

    /**
     * 头部添加子节点列表（不改变原始数据）
     */
  }, {
    key: "prependChildren",
    value: function prependChildren(datas) {
      var _this4 = this;
      datas.forEach(function (data) {
        if (_this4.tree.has(data[_this4.uniqueKey])) {
          throw new Error("".concat(data[_this4.uniqueKey], " is existed already"));
        }
      });
      datas.reverse().forEach(function (data) {
        var node = new TreeNode(data, {
          uniqueKey: _this4.uniqueKey,
          childrenKey: _this4.childrenKey,
          parent: _this4,
          tree: _this4.tree
        });
        _this4.childNodes.unshift(node);
      });
      return this;
    }

    /** 当前节点后插入（不改变原始数据） */
  }, {
    key: "after",
    value: function after(data) {
      var node = new TreeNode(data, {
        uniqueKey: this.uniqueKey,
        childrenKey: this.childrenKey,
        parent: this.parent,
        tree: this.tree
      });
      if (!this.parent) {
        this.tree.nodes.splice(this.index + 1, 0, node);
      } else {
        this.parent.childNodes.splice(this.index + 1, 0, node);
      }
      return this;
    }

    /** 当前节点前插入（不改变原始数据） */
  }, {
    key: "before",
    value: function before(data) {
      var node = new TreeNode(data, {
        uniqueKey: this.uniqueKey,
        childrenKey: this.childrenKey,
        parent: this.parent,
        tree: this.tree
      });
      if (!this.parent) {
        this.tree.nodes.splice(this.index, 0, node);
      } else {
        this.parent.childNodes.splice(this.index, 0, node);
      }
      return this;
    }

    /** 替换节点 */
  }, {
    key: "replaceWith",
    value: function replaceWith(data) {
      var node = new TreeNode(data, {
        uniqueKey: this.uniqueKey,
        childrenKey: this.childrenKey,
        parent: this.parent,
        tree: this.tree
      });
      if (!this.parent) {
        this.tree.nodes.splice(this.index, 1, node);
      } else {
        var _this$parent3;
        (_this$parent3 = this.parent) === null || _this$parent3 === void 0 || _this$parent3.childNodes.splice(this.index, 1, node);
      }
      return this;
    }

    /** 删除节点，不会改变当前节点的父节点指向（不改变原始数据） */
  }, {
    key: "remove",
    value: function remove() {
      if (!this.parent) {
        this.tree.nodes.splice(this.index, 1);
      } else {
        var _this$parent4;
        (_this$parent4 = this.parent) === null || _this$parent4 === void 0 || _this$parent4.childNodes.splice(this.index, 1);
      }
      return this;
    }
  }]);
  return TreeNode;
}();
export default TreeNode;